package pl.edu.pw.perg.compinfodb.datamodel;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;

import pl.edu.pw.perg.compinfodb.entities.Connector;
import pl.edu.pw.perg.compinfodb.entities.PhysicalElement;
import pl.edu.pw.perg.compinfodb.entities.VirtualElement;
import pl.edu.pw.perg.compinfodb.entities.utils.ConnectorComparator;
import pl.edu.pw.perg.compinfodb.manager.IConnectorManager;

public class ConnectorTableModel implements TableModel,
	IStructureTreeSelectionListener {

	private static final String ELT_IN = "Element In";
	private static final String CABLE_IN = "Cable In";
	private static final String ID_IN = "In";
	private static final String ELT_OUT = "Element Out";
	private static final String ID_OUT = "Out";
	private static final String CABLE_OUT = "Cable Out";
	private static final String[] IN_COLS_NAMES = { ELT_IN, CABLE_IN, ID_IN };
	private static final String[] OUT_COLS_NAMES = { ID_OUT, CABLE_OUT, ELT_OUT };

	private IConnectorManager connectorManager;
	private List<TableModelListener> listeners = new ArrayList<TableModelListener>();
	private boolean inputFlag;
	private String[] columnNames;
	private List<Connector> connectors = new ArrayList<Connector>();

	public static final ConnectorTableModel INPUT = new ConnectorTableModel(true);
	public static final ConnectorTableModel OUTPUT = new ConnectorTableModel(false);
	
	public ConnectorTableModel(boolean input) {
		this.inputFlag = input;
		columnNames = input ? IN_COLS_NAMES : OUT_COLS_NAMES;
	}

	public void addTableModelListener(TableModelListener l) {
		listeners.add(l);
	}

	public Class<?> getColumnClass(int columnIndex) {
		return null;
	}

	public int getColumnCount() {
		return columnNames.length;
	}

	public String getColumnName(int columnIndex) {
		return columnNames[columnIndex];
	}

	public int getRowCount() {
		return connectors.size();
	}

	public Object getValueAt(int rowIndex, int columnIndex) {
		Connector conn = connectors.get(rowIndex);

		if (getColumnName(columnIndex).equals(ID_IN)
				|| getColumnName(columnIndex).equals(ID_OUT))
			return inputFlag ? conn.getPositionIn() : conn.getPositionOut();
		if (getColumnName(columnIndex).equals(ELT_IN)
				|| getColumnName(columnIndex).equals(ELT_OUT))
			return inputFlag ? conn.getElementIn().getName() : conn.getElementOut().getName();
		if (getColumnName(columnIndex).equals(CABLE_IN)
				|| getColumnName(columnIndex).equals(CABLE_OUT))
			return conn.getCable().getName();

		throw new IllegalArgumentException("No such column!");
	}

	public boolean isCellEditable(int rowIndex, int columnIndex) {
		return false;
	}

	public void removeTableModelListener(TableModelListener l) {
		listeners.remove(l);
	}

	public void setValueAt(Object value, int rowIndex, int columnIndex) {
		throw new UnsupportedOperationException("This table not allows changes");
	}

	private void setVirtualElement(VirtualElement virtualElement) {
		if(virtualElement == null)
			return;
		Map<Integer, Connector> indicesMap = new HashMap<Integer, Connector>();
		Set<Connector> connectorSet = inputFlag ? virtualElement.getInputConnectors()
				: virtualElement.getOutputConnectors();
		for (Connector connector : connectorSet) {
			indicesMap.put(inputFlag? connector.getPositionIn() : connector.getPositionOut(), connector);
		}
		connectors.clear();
		for (int i = 0; i < (inputFlag? virtualElement.getElementType().getInputConnectorsNr() : 
			virtualElement.getElementType().getInputConnectorsNr()); i++) {
			if(indicesMap.containsKey(i))
				connectors.add(indicesMap.get(i));
			else{
				Connector empty = new Connector();
				if(inputFlag)
					empty.setPositionIn(i); 
				else
					empty.setPositionOut(i);
				connectors.add(empty);
			}
				
		}
		
//		connectors.addAll(!);
		fillEmptyElements(connectors);
		Collections.sort(connectors, new ConnectorComparator(inputFlag));
		Map<Integer, Connector> connectorsPositions = new HashMap<Integer, Connector>();
		
		for (Connector conn : connectors) {
			connectorsPositions.put(inputFlag? conn.getPositionIn() : 
				conn.getPositionOut(), conn);
		}
		int connsNumber = inputFlag? virtualElement.getElementType().getInputConnectorsNr() : 
			virtualElement.getElementType().getOutputConnectorsNr(); 
		for (int i = 0; i < connsNumber; i++) {
//			TODO: Jakos sensownie to zaimplementowac
//			(dodanie pustych polaczen)
		}
		for (TableModelListener l : listeners) {
			l.tableChanged(new TableModelEvent(this));
		}
	}

	public void setConnectorManager(IConnectorManager connectorManager) {
		this.connectorManager = connectorManager;
	}

	public void selectionChanged(VirtualElement ve) {
		setVirtualElement(ve);
	}
	
	private static void fillEmptyElements(List<Connector> connectors){
		for (Connector connector : connectors) {
			if(connector.getElementIn() == null)
				connector.setElementIn(new VirtualElement());
			if(connector.getElementOut() == null)
				connector.setElementOut(new VirtualElement());
			if(connector.getCable() == null)
				connector.setCable(new VirtualElement());
			
		}
	}

	public void selectionChanged(PhysicalElement ce) {
//		ce.
		System.out.println("dupa");
		
	}

}
